
import pandas as pd
import numpy as np
import os
import cv2 
#pip install opencv-python
#如果失败，课尝试下载wheel安装
#https://pypi.tuna.tsinghua.edu.cn/simple/opencv-contrib-python/
#可下载wheel
print(cv2.__version__)
#opencv要求路径中不能有中文字符

# 获得图片路径
source_path = r"D:\shapes\squares\drawing(81).png"

# img表示输入的图片，即为需要进行形状判断的图片
frame = cv2.imread(source_path)  #读取图片后以多维数组的形式保存图片信息，前两维表示图片的像素坐标，最后一维表示图片的通道索引，具体图像的通道数由图片的格式来决定
h, w, ch = frame.shape
result = np.zeros((h, w, ch), dtype=np.uint8)
# 二值化图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #函数来改变图像的颜色空间
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)  #阈值的作用是根据设定的值处理图像的灰度值，比如灰度大于某个数值像素点保留。通过阈值以及有关算法可以实现从图像中抓取特定的图形，比如去除背景等
#cv2.imshow("input image", frame)
#print(cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE))

contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)


# cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])  → image, contours, hierarchy
#
#
# image-寻找轮廓的图像；
#
# mode-轮廓的检索模式：
#     cv2.RETR_EXTERNAL表示只检测外轮廓
#     cv2.RETR_LIST检测的轮廓不建立等级关系
#     cv2.RETR_CCOMP建立两个等级的轮廓，上面的一层为外边界，里面的一层为内孔的边界信息。如果内孔内还有一个连通物体，这个物体的边界也在顶层。
#     cv2.RETR_TREE建立一个等级树结构的轮廓。
#
# method-为轮廓的近似办法：
#     cv2.CHAIN_APPROX_NONE存储所有的轮廓点，相邻的两个点的像素位置差不超过1，即max（abs（x1-x2），abs（y2-y1））==1
#     cv2.CHAIN_APPROX_SIMPLE压缩水平方向，垂直方向，对角线方向的元素，只保留该方向的终点坐标，
#
# 例如一个矩形轮廓只需4个点来保存轮廓信息
#     cv2.CHAIN_APPROX_TC89_L1，CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
#
#
# 返回值
#
# cv2.findContours()函数返回两个值，一个是轮廓本身(countours)，还有一个是每条轮廓对应的属性(hierarchy)。


for cnt in range(len(contours)):
    # 提取与绘制轮廓
    cv2.drawContours(result, contours, cnt, (0, 255, 0), 2)
    # 第一个参数是指明在哪幅图像上绘制轮廓；image为三通道才能显示轮廓
    # 第二个参数是轮廓本身，在Python中是一个list;
    # 第三个参数指定绘制轮廓list中的哪条轮廓，如果是 - 1，则绘制其中的所有轮廓。后面的参数很简单。其中thickness表明轮廓线的宽度，如果是 - 1（cv2.FILLED），则为填充模式。
    # 轮廓逼近
    epsilon = 0.05 * cv2.arcLength(contours[cnt], True)

    # 也称为弧长，可以使用函数cv2.arcLenngth()
    # 计算得到。这个函数的第二参数可以用来指定对象的形状是闭合（True），还是打开的（一条曲线）。
    approx = cv2.approxPolyDP(contours[cnt], epsilon, True) # 将轮廓形状近似到另外一种有更少点组成的轮廓形状，新轮廓的点的数目有我们设定的准确度来决定。假设我们要在一幅图像中查找一个矩形，但是由于图像的种种原因，我们不能得到一个完美的矩形，而是一个不规则形状，现在就可以使用这个函数来近似这个形状了。这个函数的第二个参数叫epsilon，它是从原始轮廓到近似轮廓的最大距离，它是一个准确率参数，选择一个好的epsilon对于得到满意结果非常重要。

    #print(approx)
    # 分析几何形状
    corners = len(approx)
    print(corners)
    shape_type = ""
    if corners == 3:
        shape_type = "三角形"
        print(shape_type)
    if corners == 4:
        shape_type = "矩形"
        print(shape_type)
    if corners > 4:
        shape_type = "圆形"
        print(shape_type)
#